// 原理包含三部分：
// 1- 解析器（compile):也常被称为编译器。负责对视图中的指令元素进行扫描解析，对其实现指令的初始化，以及生成订阅者。
// 2- 订阅者（Watcher):负责接收更新的数据，根据数据更新视图（view).每一个数据可能对应多个订阅者。
// 3- 观察者（observer）:也被称为监听者。负责对所有数据进行监听，如果数据发生改变会通知该数据对应的所有订阅者。
function Zhang(config={}){
    // 设置挂载的位置元素
    this.$el = document.querySelector(config.el);
    // 生成$data
    this.$data = config.data;
    // 与$data的结构相同(拥有与$data相同的属性，其值是一个数组，数组的元素是订阅者)
    this.binds = {};
    // 调用观察者
    this.observer();
    // 调用解析器
    this.compile();
}
Object.assign(Zhang.prototype,{
    // 观察者：对所有数据进行动持。
    observer(){
        for(let key in this.$data){
            this.binds[key] = [];
            Object.defineProperty(this,key,{
                get(){
                    return this.$data[key];
                },
                set(v){
                    this.$data[key]= v;
                    this.binds[key].forEach(update=>update())
                }
            })
        }
    },
    // 解析器
    compile(){
        // 获取所有的子元素节点
        const nodes = this.$el.children;
        for(let i = 0;i<nodes.length;i++){
            // 获取要解析的元素。
            const node = nodes[i];
            // 判断元素是否拥有z-model属性
            if(node.hasAttribute("z-model")){
                const attrValue = node.getAttribute("z-model");
                // 1- 将元素的value值进行初始化。
                node.value = this[attrValue];
                // 2- 增加input事件,更新数据状态。
                node.addEventListener("input",function(e){
                    this[attrValue] = e.target.value;
                }.bind(this));

                // 增加订阅者
                this.binds[attrValue].push(()=>{
                    node.value = this[attrValue];
                });
            }
            // 判断元素是否拥有z-text属性
            if(node.hasAttribute("z-text")){
                const attrValue = node.getAttribute("z-text");
                node.innerText = this[attrValue];

                // 增加订阅者
                this.binds[attrValue].push(()=>{
                    node.innerText = this[attrValue];
                });
            }
            // 判断元素是否拥有z-html属性
            if(node.hasAttribute("z-html")){
                const attrValue = node.getAttribute("z-html");
                node.innerHTML = this[attrValue];

                // 增加订阅者
                this.binds[attrValue].push(()=>{
                    node.innerHTML = this[attrValue];
                });
            }
        }
    }
})